from elixir import session
from ui.GladeBase import GladeBase
from utils.Environment import logger, envir
from utils import string_hook
from data.models import Bookshop, Address
from ui import get_save_dialog, mandatory_data_error, BOOKSHOP,\
    check_authorization, get_info_dialog
from ui.treemodels import BookshopListStore
from sqlalchemy.orm.exc import NoResultFound

import gtk

NO_ENTITY = -1

class ManageBookshop(GladeBase):
    def __init__(self, query=Bookshop.query, top_component=None):
        logger.debug("UI: %s instance created" % self.__class__)
        GladeBase.__init__(self, 'manage_bookshop_frame', top_component)
        self._init_gui_components()
        
        # Setting up bookshop list
        cell = gtk.CellRendererText()
        tvc = gtk.TreeViewColumn('Bookshop')
        tvc.pack_start(cell, True)
        tvc.set_attributes(cell,text=1)
        self.bookshop_treeview.append_column(tvc)
        self.bookshop_frame_hpaned.set_position(400)
        
        # Authorization setup
        if check_authorization(envir.get_user(), BOOKSHOP):
            query = query.filter_by(id=envir.get_user().subject.id)
            self.delete_button.set_sensitive(False)
            self.new_button.set_sensitive(False)
            self._load_to_gui(envir.get_user().subject.id)
        else:
            self.entity_key = NO_ENTITY
        
        self.bookshop_list = BookshopListStore(Bookshop, query.all)
        self.bookshop_treeview.set_model(self.bookshop_list)
        
        self.entity_key = NO_ENTITY
    
    def _init_gui_components(self):
        """
        Intialize gui components as needed. This is useful in the contructor or 
        binded with particular actions (for instance, a "clear" button, or "new" button) 
        """
        self.name_entry.set_text("")
        self.vat_entry.set_text("")
        self.iban_entry.set_text("")
        self.head_address_entry.set_text("")
        self.head_city_entry.set_text("")
        self.head_postal_entry.set_text("")
        self.head_prov_entry.set_text("")
        self.head_country_entry.set_text("")
        self.reg_address_entry.set_text("")
        self.reg_city_entry.set_text("")
        self.reg_postal_entry.set_text("")
        self.reg_prov_entry.set_text("")
        self.reg_country_entry.set_text("")
        self.reg_address_checkbutton.set_active(False)
        self.reg_address_checkbutton.toggled()
        self.apply_button.set_sensitive(False)

    def _retrieve_components(self):
        """
        Retrieve all used gui components from builder. This method is called in the
        GladeBase constructor
        """
        self.get_from_builder('apply_button')
        self.get_from_builder('delete_button')
        self.get_from_builder('new_button')
        self.get_from_builder('bookshop_treeview')
        self.get_from_builder('name_entry')
        self.get_from_builder('vat_entry')
        self.get_from_builder('iban_entry')
        self.get_from_builder('head_address_entry')
        self.get_from_builder('head_city_entry')
        self.get_from_builder('head_postal_entry')
        self.get_from_builder('head_prov_entry')
        self.get_from_builder('head_country_entry')
        self.get_from_builder('reg_address_entry')
        self.get_from_builder('reg_city_entry')
        self.get_from_builder('reg_postal_entry')
        self.get_from_builder('reg_prov_entry')
        self.get_from_builder('reg_country_entry')
        self.get_from_builder('reg_address_checkbutton')
        self.get_from_builder('reg_address_table')
        self.get_from_builder('bookshop_frame_hpaned')
    
    def _has_valid_data(self):
        """
        Formal control for data in the input form.
        @return: boolean. 'True' when data is valid
        """
        
        name = self.name_entry.get_text()
        vat = self.vat_entry.get_text()
        iban = self.iban_entry.get_text()
        head_address = self.head_address_entry.get_text()
        head_city = self.head_city_entry.get_text()
        
        if not name:
            mandatory_data_error('Company Name', self.name_entry)
            return False
        
        if not vat:
            mandatory_data_error('Vat Number', self.vat_entry)
            return False
        
        if not head_address:
            mandatory_data_error('Address', self.head_address_entry)
            return False
        
        if not head_city:
            mandatory_data_error('City', self.head_city_entry)
            return False
        
        # TODO: add vat lenght and format control 
        # TODO: add iban format control when iban is inserted
        
        # Perform checks on registered address only when user choose to input address data
        if not self.reg_address_checkbutton.get_active():
            return True 
        
        reg_address = self.reg_address_entry.get_text()
        reg_city = self.reg_city_entry.get_text()
        
        if not reg_address:
            mandatory_data_error('Address', self.reg_address_entry)
            return False
        
        if not reg_city:
            mandatory_data_error('City', self.reg_city_entry)
            return False
        
        return True    
    
    def _load_to_gui(self, id):
        self.entity_key = id
        bookshop = Bookshop.get_by(id=self.entity_key)
        
        self.name_entry.set_text(bookshop.company_name)
        self.vat_entry.set_text(bookshop.vat)
        self.iban_entry.set_text(string_hook(bookshop.iban))
        
        head_address = Address.query.with_parent(bookshop, property='addresses').filter_by(type='head').one()
        self.head_address_entry.set_text(head_address.address)
        self.head_city_entry.set_text(head_address.city)
        self.head_postal_entry.set_text(string_hook(head_address.postalcode))
        self.head_prov_entry.set_text(string_hook(head_address.province))
        self.head_country_entry.set_text(string_hook(head_address.country))
        
        try:
            reg_address = Address.query.with_parent(bookshop, property='addresses').filter_by(type='registered').one()
            self.reg_address_checkbutton.set_active(True)
            self.reg_address_entry.set_text(reg_address.address)
            self.reg_city_entry.set_text(reg_address.city)
            self.reg_postal_entry.set_text(string_hook(reg_address.postalcode))
            self.reg_prov_entry.set_text(string_hook(reg_address.province))
            self.reg_country_entry.set_text(string_hook(reg_address.country))
        except NoResultFound:
            pass
        
        self.apply_button.set_sensitive(False)
    
    def _save_data(self):
        """
        Save changes to db. 
        @return: 'True' if data have been successfully saved 
        """
        if not self._has_valid_data():
            return False
        
        # manage Bookshop data object
        if self.entity_key == NO_ENTITY:
            bookshop = Bookshop()
            head_address = Address()
            bookshop.addresses.append(head_address)
        else:
            bookshop = Bookshop.get_by(id=self.entity_key)
            head_address = Address.query.with_parent(bookshop, property='addresses').filter_by(type='head').one()
        
        bookshop.company_name = self.name_entry.get_text()
        bookshop.vat = self.vat_entry.get_text()
        bookshop.iban = string_hook(self.iban_entry.get_text())
        
        head_address.address = self.head_address_entry.get_text()
        head_address.city = self.head_city_entry.get_text()
        head_address.postalcode = string_hook(self.head_postal_entry.get_text())
        head_address.province = string_hook(self.head_prov_entry.get_text())
        head_address.country = string_hook(self.head_country_entry.get_text())
        
        try:
            reg_address = Address.query.with_parent(bookshop, property='addresses').filter_by(type='registered').one()
        except NoResultFound:
            reg_address = None
            
        reg_address_active = self.reg_address_checkbutton.get_active()
        if reg_address_active:
            if not reg_address:
                reg_address = Address()
            reg_address.type = 'registered'
            reg_address.address = self.reg_address_entry.get_text()
            reg_address.city = self.reg_city_entry.get_text()
            reg_address.postalcode = string_hook(self.reg_postal_entry.get_text())
            reg_address.province = string_hook(self.reg_prov_entry.get_text())
            reg_address.country = string_hook(self.reg_country_entry.get_text())
            
            # FIXME:
            # append() is giving me some problems because it causes autoflush while subject_id 
            # is still None which is manadtory, so this raise an OperationalError
            #bookshop.addresses.append(reg_address)
            # ...this way works... 
            reg_address.subject = bookshop
        elif reg_address:
            reg_address.delete()
        
        # save changes
        session.commit()
        
        if self.entity_key == NO_ENTITY:
            self.bookshop_list.add(bookshop)
        
        self.entity_key = bookshop.id
        self.apply_button.set_sensitive(False)
        return True
    
    # Signals
    def on_new_button_clicked(self, object, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                
        self._init_gui_components()
        self.bookshop_treeview.get_selection().unselect_all()
        self.entity_key = NO_ENTITY
    
    def on_apply_button_clicked(self, object, data=None):
        self._save_data()
    
    def on_delete_button_clicked(self, object, data=None):
        (model, iter) = self.bookshop_treeview.get_selection().get_selected()
        if not iter:
            return 
        
        entity = model.get_entity(iter) 
        if len(entity.orders) > 0:
            get_info_dialog(self.get_top_component(), 
                            "Selected bookshop can't be deleted because order/s have been inserted.\n" \
                            "Check and remove orders first.")
            return
        
        model.remove(iter)
        entity.delete()
        self._init_gui_components()
        self.entity_key = NO_ENTITY
        session.commit()
        
    def on_bookshop_changed(self, *args, **kwargs):
        self.apply_button.set_sensitive(True)
    
    def on_bookshop_treeview_row_activated(self, treeview, path, view_column, data=None):
        if self.apply_button.get_property('sensitive'):
            res = get_save_dialog(self.get_top_component(), "Save changes?")
            if res == gtk.RESPONSE_OK:
                if not self._save_data():
                    return
                    
        self._init_gui_components()
        
        self._load_to_gui(self.bookshop_list[path][0])
    
    def on_reg_address_checkbutton_toggled(self, checkbutton, data=None):
        self.reg_address_table.set_sensitive(checkbutton.get_active())
        self.on_bookshop_changed(checkbutton, data)    